package com.ebo.httpcall4j.core.repository;

import com.ebo.httpcall4j.core.model.HttpCallLog;
import com.ebo.httpcall4j.core.model.enums.ContentType;
import org.springframework.dao.EmptyResultDataAccessException;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.jdbc.support.GeneratedKeyHolder;
import org.springframework.jdbc.support.KeyHolder;
import org.springframework.stereotype.Repository;

import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.List;
import java.util.Optional;

/**
 * http调用日志仓库实现类
 */
@Repository
public class JdbcHttpCallLogRepository implements HttpCallLogRepository {

    private final JdbcTemplate jdbcTemplate;

    public JdbcHttpCallLogRepository(JdbcTemplate jdbcTemplate) {
        this.jdbcTemplate = jdbcTemplate;
    }

    @Override
    public Long save(HttpCallLog log) {
        String sql = "INSERT INTO http_call_log (url, method, content_type, headers, body, response_status_code, response_body, status, rerun_of_log_id, system_name, function_name, processor_name, extensions, ip) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
        KeyHolder keyHolder = new GeneratedKeyHolder();
        jdbcTemplate.update(connection -> {
            PreparedStatement ps = connection.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS);
            ps.setString(1, log.getUrl());
            ps.setString(2, log.getMethod());
            ps.setString(3, log.getContentType().getValue());
            ps.setString(4, log.getHeaders());
            ps.setString(5, log.getBody());
            ps.setInt(6, log.getResponseStatusCode());
            ps.setString(7, log.getResponseBody());
            ps.setString(8, log.getStatus());
            ps.setObject(9, log.getRerunOfLogId());
            ps.setString(10, log.getSystemName());
            ps.setString(11, log.getFunctionName());
            ps.setString(12, log.getProcessorName());
            ps.setString(13, log.getExtensions());
            ps.setString(14, log.getIp());
            return ps;
        }, keyHolder);
        return keyHolder.getKey().longValue();
    }

    @Override
    public Optional<HttpCallLog> findById(Long id) {
        String sql = "SELECT * FROM http_call_log WHERE id = ?";
        try {
            return Optional.ofNullable(jdbcTemplate.queryForObject(sql, new HttpCallLogRowMapper(), id));
        } catch (EmptyResultDataAccessException e) {
            return Optional.empty();
        }
    }

    @Override
    public List<HttpCallLog> findFailedLogs() {
        String sql = "SELECT * FROM http_call_log WHERE status = 'FAILED'";
        return jdbcTemplate.query(sql, new HttpCallLogRowMapper());
    }

    private static class HttpCallLogRowMapper implements RowMapper<HttpCallLog> {
        @Override
        public HttpCallLog mapRow(ResultSet rs, int rowNum) throws SQLException {
            HttpCallLog log = new HttpCallLog();
            log.setId(rs.getLong("id"));
            log.setUrl(rs.getString("url"));
            log.setMethod(rs.getString("method"));
            log.setContentType(ContentType.fromValue(rs.getString("content_type")));
            log.setHeaders(rs.getString("headers"));
            log.setBody(rs.getString("body"));
            log.setResponseStatusCode(rs.getInt("response_status_code"));
            log.setResponseBody(rs.getString("response_body"));
            log.setStatus(rs.getString("status"));
            log.setRerunOfLogId(rs.getLong("rerun_of_log_id"));
            log.setSystemName(rs.getString("system_name"));
            log.setFunctionName(rs.getString("function_name"));
            log.setProcessorName(rs.getString("processor_name"));
            log.setExtensions(rs.getString("extensions"));
            log.setCreatedAt(rs.getTimestamp("created_at").toLocalDateTime());
            return log;
        }
    }
}